﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using NewsAggregatorLibrary;


namespace RSSCrawler
{
    public class Channel
    {
        public string Title { get; set; }
        public string Link { get; set; }
        public string Description { get; set; }
        public IEnumerable<Item> Items { get; set; }
    }

    public class Item
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string Link { get; set; }
        public string PublishDate { get; set; }
    }

    /// <summary>
    /// RSS manager to read rss feeds
    /// </summary>
    public static class RssManager
    {
        private const string _KEYWORD_REGEX = "(name)(=)(\"keywords\")(\\s+)(content)(=)(\".*?\")";
        static void Main(string[] args)
        {
            FeedsMemberCollection feedsList = FeedsMember.RetrieveAll();
            foreach(FeedsMember f in feedsList){
                Console.WriteLine(" URL : {0} \r\n", f.FeedUrl);
                ReadFeed(f.FeedUrl, f.Id, (int)f.CategoryID);
            }
            Console.ReadLine();
        }
        

        /// <summary>
        /// Reads the relevant Rss feed and returns a list off RssFeedItems
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static List<Item> ReadFeed(string url, int feedID, int categoryID)
        {
            //create a new list of the rss feed items to return
            List<Item> rssFeedItems = new List<Item>();

            try
            {
                var myFeed = getChannelQuery(XDocument.Load(new StreamReader(HttpWebRequest.Create(url).GetResponse().GetResponseStream())));
                foreach (var item in myFeed)
                {
                    //Console.WriteLine("{0} - {1} \r\n", item.Title, item.Description);
                   
                    foreach (var i in item.Items)
                    {
                        //Console.WriteLine("{0} \r\n", i.PublishDate.Substring(0, i.PublishDate.LastIndexOf(' ')));                        
                        int storyID = StoriesMember.AddStory(feedID, i.Title, i.Link, i.Description, Convert.ToDateTime(i.PublishDate.Substring(0, i.PublishDate.LastIndexOf(' '))), categoryID);
                        string htmlText = GetWebText(i.Link);
                        MatchCollection matches = Regex.Matches(htmlText, _KEYWORD_REGEX);
                        if (matches.Count > 0)
                        {
                            //add keywords
                            string keywords = matches[0].Value;
                            keywords = keywords.ToLower();
                            keywords = keywords.Substring(keywords.IndexOf("content=\"")+9);
                            keywords = keywords.Trim('"');
                            string[] keywordsArray = keywords.Split(',');
                            foreach (string keyword in keywordsArray)
                            {
                                if (keyword.Trim() != "")// if not an empty keyword
                                {
                                    //check if keyword exists and adds it if it doesnt
                                    KeywordsMember keywordsMember = KeywordsMember.RetrieveByKeyword(keyword.Trim()) ??
                                                                    KeywordsMember.RetrieveByID(
                                                                        KeywordsMember.AddKeyword(keyword.Trim()));
                                    //Create relation between keyword and story
                                    if (RelationMember.RetrieveByStoryIDKeyID(storyID, keywordsMember.Id) == null)
                                    {
                                        RelationMember.AddRelation(keywordsMember.Id, storyID);
                                    }
                                }
                            }
                        }
                    }
                    //Console.WriteLine("\r\n");
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("{0} Exception caught.", e);
            }
            //return the rss feed items
            return rssFeedItems;
        }

        /// <summary>
        /// Gets the response text for a given url.
        /// </summary>
        /// <param name="url">The url whose text needs to be fetched.</param>
        /// <returns>The text of the response.</returns>
        private static string GetWebText(string url)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.UserAgent = "A .NET Web Crawler";

            WebResponse response = request.GetResponse();

            Stream stream = response.GetResponseStream();

            StreamReader reader = new StreamReader(stream);
            string htmlText = reader.ReadToEnd();
            return htmlText;
        }


        static IEnumerable<Channel> getChannelQuery(XDocument xdoc)
        {
            return from channels in xdoc.Descendants("channel")
                   select new Channel
                   {
                       Title = channels.Element("title") != null ? channels.Element("title").Value : "",
                       Link = channels.Element("link") != null ? channels.Element("link").Value : "",
                       Description = channels.Element("description") != null ? channels.Element("description").Value : "",
                       Items = from items in channels.Descendants("item")
                        select new Item
                        {
                            Title = items.Element("title") != null ? items.Element("title").Value : "",
                            Link = items.Element("link") != null ? items.Element("link").Value : "",
                            Description = items.Element("description") != null ? items.Element("description").Value : "",
                            PublishDate = items.Element("pubDate") != null ? items.Element("pubDate").Value : (items.Element("date") != null ? items.Element("date").Value : "")
                        }
                   };
        }

    }
}